#include "pTrigger.h"
#include "pMaterial.h"
#include "map.h"
#include "entity.h"
#include "pPlayer.h"
#include "physics.h"

using namespace tmpl;

pTrigger::pTrigger( unsigned int aIndex, vector3 aPos, float aAngle, PHYSICS_MODE aMode )
: pBody(aIndex, aPos, aAngle, aMode)
{

}

void pTrigger::AddTriggerCallBack( pTriggerCallBack* aCallback )
{
	aCallback->mTrigger = this;
	mCallBacks.push_back(aCallback);
}

void pTrigger::AddBox( vector3 aPos, vector3 aSize, float aAngle, pMaterial* aMat )
{
	b2FixtureDef fdef = aMat->GetFixture();
	b2PolygonShape shape = b2PolygonShape();

	aPos = aPos * SCALE_IN;
	aSize = aSize * SCALE_IN;

	shape.SetAsBox(aSize.x/2, aSize.y /2, b2Vec2(aPos.x, aPos.y), aAngle);
	fdef.shape = &shape;
	fdef.userData = aMat;
	fdef.isSensor = true;
	mBody->CreateFixture(&fdef);
}

void pTrigger::AddCircle( vector3 aPos, float aRadius, pMaterial* aMat )
{
	b2FixtureDef fdef= aMat->GetFixture();
	fdef.userData = aMat;
	b2CircleShape shape = b2CircleShape();

	aPos = aPos * SCALE_IN;
	aRadius = aRadius * SCALE_IN;

	shape.m_p.Set(aPos.x, aPos.y);
	shape.m_radius = aRadius;
	fdef.shape = &shape;
	fdef.userData = aMat;
	fdef.isSensor = true;
	mBody->CreateFixture(&fdef);
}

void pTrigger::AddVertices( b2Vec2 *aVertices, unsigned int aNumberOfVertices, pMaterial* aMat, b2Vec2 aOffset )
{
	b2FixtureDef fdef = aMat->GetFixture();
	b2PolygonShape shape = b2PolygonShape();

	b2Vec2 CenterPoint = (aVertices[0] + aVertices[1] + aVertices[2]);
	CenterPoint.x /= 3.0f;
	CenterPoint.y /= 3.0f;

	for(unsigned int i = 0; i < aNumberOfVertices; i++)
	{
		aVertices[i] += aOffset;
		aVertices[i] -= CenterPoint;
		aVertices[i] *= 1.2f;
		aVertices[i] += CenterPoint;

		aVertices[i] *= SCALE_IN;
	}

	shape.Set(aVertices, aNumberOfVertices);
	fdef.shape = &shape;
	fdef.isSensor = true;
	fdef.userData = aMat;

	mBody->CreateFixture(&fdef);
}

void pTrigger::AddLine( vector3 aPos1, vector3 aPos2, pMaterial* aMat )
{
	b2FixtureDef fdef = aMat->GetFixture();
	b2PolygonShape shape = b2PolygonShape();
	
	aPos1 = aPos1 * SCALE_IN;
	aPos2 = aPos2 * SCALE_IN;

	shape.SetAsEdge(b2Vec2(aPos1.x, aPos1.y), b2Vec2(aPos2.x, aPos2.y));
	fdef.shape = &shape;

	fdef.userData = aMat;
	fdef.isSensor = true;

	mBody->CreateFixture(&fdef);
}

void tmpl::pTrigger::Tick()
{
	for(unsigned int i = 0; i < mCallBacks.size(); i++)
	{
		mCallBacks[i]->Tick();
	}
}

void tmpl::pTriggerCallBack::Tick()
{
	if(mDisabled) return;
	b2ContactEdge* list = mTrigger->mBody->GetContactList();
	IsInside = false;
	for (; list != 0; list = list->next)
	{
		b2Contact* contact = list->contact;

		// fixture A
		void* data = contact->GetFixtureA()->GetBody()->GetUserData();
		pEntity* entitybase = (pEntity*)data;
		if(entitybase != 0 && entitybase->GetType() == ENTITY_PLAYER)
		{
			if(contact->IsTouching())
			{
				IsInside = true;
			}
		}
		else if (entitybase != 0 && entitybase->GetType() == ENTITY_BODY)
		{
			BodyInside((pBody*)entitybase);
		}

		// fixture B
		data = contact->GetFixtureB()->GetBody()->GetUserData();
		entitybase = (pEntity*)data;
		if(entitybase != 0 && entitybase->GetType() == ENTITY_PLAYER)
		{
			if(contact->IsTouching())
			{
				IsInside = true;
			}
		}
		else if (entitybase != 0 && entitybase->GetType() == ENTITY_BODY)
		{
			BodyInside((pBody*)entitybase);
		}
	}
	if(!WasInsideLastTick && IsInside)
	{
		OnEnter();
	}
	if(WasInsideLastTick && IsInside)
	{
		WhileInside();
	}
	if(WasInsideLastTick && !IsInside)
	{
		OnExit();
	}
	WasInsideLastTick = IsInside;
}

pTriggerGoToNextLevel::pTriggerGoToNextLevel( Map* aMap )
{
	mMap = aMap;
}

void pTriggerGoToNextLevel::OnEnter()
{
	mMap->SetLoadNextMap(true);
}

void pTriggerGoToLevel::OnEnter()
{
	mMap->SetNextMap(mLevel);
	mMap->SetLoadNextMap(true);
}

pTriggerGoToLevel::pTriggerGoToLevel( char* aLevel, Map* aMap )
{
	mMap = aMap;
	strcpy(mLevel, aLevel);
}

pTriggerPickupItem::pTriggerPickupItem( Map* aMap, Entity* aImageObject )
{
	mMap = aMap;
	mImageObject = aImageObject;
}

void pTriggerPickupItem::OnEnter()
{
	mMap->PlayerPickedUpItem();
	mImageObject->SetRenderType(Entity::RENDER_TYPE::RENDER_NOTHING);
	mDisabled = true; // only use once
}

pTriggerWater::pTriggerWater(vector3 aWaterSurfacePosition)
{
	mWaterSurfacePosition = aWaterSurfacePosition;
	mPlayer = 0;
}

void pTriggerWater::OnEnter()
{
	mPlayer = Physics::mInstance->GetPlayer();
}

void pTriggerWater::WhileInside()
{
	for(unsigned int i = 0; i < P_BALLS_PER * P_CENTERS; i++)
	{
		b2Body* body = mPlayer->GetBody(i);
		b2Vec2 pos = body->GetPosition();
		float dist = mWaterSurfacePosition.y - pos.y;
		if(dist < 0.0f)
		{
			b2Vec2 vel = body->GetLinearVelocity();
			vel.x *= 0.9f;
			vel.y *= 0.9f;
			vel.y -= 0.5f;
			body->SetLinearVelocity(vel);
		}
	}

	/*
	// body1:
	b2Vec2 PlayerPos1 = mPlayer->GetSensorBody(0)->GetPosition();
	float Force1 = mWaterSurfacePosition.y - PlayerPos1.y;
	if(Force1 > 150.0f)
	{
		mPlayer->SetVelocity(0, mPlayer->GetVelocity(0) * 0.9f);
		mPlayer->AddVelocity(0, vector3(0.0f, -0.3f, 0.0f));	
	}

	// body2:
	b2Vec2 PlayerPos2 = mPlayer->GetSensorBody(1)->GetPosition();
	float Force2 = mWaterSurfacePosition.y - PlayerPos2.y;
	
	if(Force2 > 150.0f)
	{
		mPlayer->SetVelocity(1, mPlayer->GetVelocity(1) * 0.9f);
		mPlayer->AddVelocity(1, vector3(0.0f, -0.3f, 0.0f));
	}
	*/
}


void pTriggerWater::BodyInside(pBody* aBody)
{
	b2Body* bBody = aBody->Get2DBoxBody();
	b2Vec2 pos = bBody->GetPosition();
	float dist = mWaterSurfacePosition.y - pos.y;
	if(dist < 0.0f)
	{
		b2Vec2 vel = bBody->GetLinearVelocity();
		vel.x *= 0.9f;
		vel.y *= 0.9f;
		vel.y -= 0.25f;
		float anglev = bBody->GetAngularVelocity();
		anglev*= 0.9;
		bBody->SetLinearVelocity(vel);
		bBody->SetAngularVelocity(anglev);

	}

	//
	//float angle = bBody->GetAngle();
	//int anglei = (int)(angle*10000.0);
	//anglei = anglei % (int)(PI*10000.0);
	//angle = ((float)anglei)/10000.0;
	//if(angle > 0 && angle < PI/2)
	//{
	//	bBody->ApplyTorque(-0.5);
	//}
	//if(angle > PI/2 && angle < PI)
	//{
	//	bBody->ApplyTorque(0.5);
	//}
	//if(angle > PI && angle < PI*1.5)
	//{
	//	bBody->ApplyTorque(-0.5);
	//}
	//if(angle > PI*1.5 && angle > PI * 2)
	//{
	//	bBody->ApplyTorque(0.5);
	//}

	
}